/*
 * This file is part of ddesktop: remote desktop system for iPad 
 *
 * Copyright (C) 2010 Kazuhiro Satoh
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. if not, see <http://www.gnu.org/licenses/>.
 */

#import <QuartzCore/QuartzCore.h>
#import <mach/mach_time.h>

#import "RemoteViewController.h"


@interface MyScrollView : UIScrollView
@end

@implementation MyScrollView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	[[self nextResponder] touchesBegan:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	[[self nextResponder] touchesEnded:touches withEvent:event];
}
@end



@interface RemoteViewController ()
- (void)sendMouseEvent:(enum DDUIEventType)eventType x:(int)x y:(int)y;
@end


@implementation RemoteViewController

@synthesize mode = _mode;
@synthesize mouseAction = _mouseAction;
@synthesize windowAction = _windowAction;
@synthesize mouseWheelSensitivity = _mouseWheelSensitivity;


// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
	//[super loadView];
	
	self.wantsFullScreenLayout = NO;

	{ // init scrollView
		_scrollView = [[MyScrollView alloc] init];
		_scrollView.backgroundColor = [UIColor blackColor];
		[_scrollView setDelegate:self];
		[_scrollView setMinimumZoomScale:1.0];
		[_scrollView setMaximumZoomScale:3.0];
		self.view = _scrollView;
	}
	
	{ // init desktopView
		_desktopView = [[UIView alloc] init];
		[self.view addSubview: _desktopView];
		[_desktopView release];
	}
	
	{ // init imageLayer
		_imageLayer = [CALayer layer];
		[_imageLayer removeAllAnimations];
		_imageLayer.contentsGravity = kCAGravityResize;
		[_desktopView.layer addSublayer:_imageLayer];
	}

	{ // init gestures
		//pan gesture
		UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]
											 initWithTarget:self action:@selector(handlePanGesture:)];
		pan.minimumNumberOfTouches = 1;
		pan.maximumNumberOfTouches = 1;
		pan.cancelsTouchesInView = NO;
		[_scrollView addGestureRecognizer:pan];
		[pan release];
	}

	_ddclientPort = nil;
	
	_drawFrameCt = 0;
	_mode = RV_MOUSE_MODE;
	_mouseAction = RV_MOUSE_ACTION_LEFT;
	_windowAction = RV_WINDOW_ACTION_MOVE;
}


- (bool)startSessionWithPort:(DDClientPort*) port
{
	_ddclientPort = [port retain];
	_scrollView.contentOffset = CGPointMake(0.0, 0.0);
	_scrollView.zoomScale = 1.0;
	_desktopView.frame = CGRectMake(0, 0, _ddclientPort.screenSize.width, _ddclientPort.screenSize.height);
	[_scrollView setContentSize:_desktopView.frame.size];
	[self updatePeepFrame];
	
	if([_ddclientPort startDownloading] == FALSE){
		return false;
	}
	return true;
}


- (bool)stopSession
{
	if(_ddclientPort != nil){
		[_ddclientPort stopDownloading];
		[_ddclientPort release];
		_ddclientPort = nil;
	}
	
	return true;
}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Overriden to allow any orientation.
    return YES;
}


- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    
    // Release any cached data, images, etc that aren't in use.
}


- (void)dealloc {
	[super dealloc];
	[self stopSession];
}


- (void)closeAllConnection{
	if(_ddclientPort != nil){
		[_ddclientPort close];
		[_ddclientPort release];
		_ddclientPort = [[DDClientPort alloc]init];
	}	
}


-(bool)updateView
{	
/*	mach_timebase_info_data_t timebase;	
	uint64_t start_time, end_time;
	mach_timebase_info(&timebase);
	start_time = mach_absolute_time();
*/
	if(_ddclientPort == nil)
	{
		return false;
	}
	
	ImageBuf* imageBufPt = [_ddclientPort imageBufPt];
	CGRect rect = CGRectMake(imageBufPt->x,
							 imageBufPt->y,
							 imageBufPt->width,// * imageBufPt->zoomScale,
							 imageBufPt->height);// * imageBufPt->zoomScale);

	//[_ddclientPort downloadFrame:_peepFrame];
	
	//[(RemoteView*)self.view changeImageToBuf:imageBufPt->buf length:(imageBufPt->headerSize + imageBufPt->dataSize) rect:rect];

	CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, imageBufPt->buf, imageBufPt->headerSize + imageBufPt->dataSize, NULL);
	CGImageRef desktopImage;
	desktopImage = CGImageCreateWithJPEGDataProvider(provider, nil, false, kCGRenderingIntentDefault);
	CGDataProviderRelease(provider);
	
	[CATransaction begin];
	[CATransaction setValue:[NSNumber numberWithFloat:0.0f] forKey:kCATransactionAnimationDuration];
	_imageLayer.contents = (id)desktopImage;
	_imageLayer.frame = rect;
	[CATransaction commit];
	
	CGImageRelease(desktopImage);

	[_desktopView setNeedsDisplay];
	
	_drawFrameCt++;

	//printf("DrawFrameCt=%d DownloadFrameCt=%d", _drawFrameCt, _ddclientPort.downloadFrameCt);
	//puts("");

	//end_time = mach_absolute_time();
	//NSLog(@"dt:%qu", ((end_time - start_time) * timebase.numer / timebase.denom) / 1000000);
	
	return true;
}


- (void)handlePanGesture:(id)sender
{
	UIPanGestureRecognizer* pan = (UIPanGestureRecognizer*)sender;
	static CGPoint beforeLocation;
	static int beforeNumTouches = 0;
	CGPoint location;
	int numTouches = [pan numberOfTouches];
	
	if(numTouches == 1){
		location = [pan locationInView:_desktopView];
		
		if(_mode == RV_MOUSE_MODE){
			[self sendMouseEvent:DD_MOUSE_BUTTON_MOVE x:location.x y:location.y];
		}
		else if(_mode == RV_WHEEL_MODE && beforeNumTouches == 1){
			int diffX = ceil((location.x - beforeLocation.x) * _mouseWheelSensitivity);
			int diffY = ceil((location.y - beforeLocation.y) * _mouseWheelSensitivity);
			[_ddclientPort sendUIEvent:DD_MOUSE_WHEEL eventOwner:DD_MOUSE_MIDDLE_BUTTON param1:diffX param2:diffY];
		}
		else if(_mode == RV_WINDOW_MODE && beforeNumTouches == 1){
			int diffX = ceil(location.x - beforeLocation.x);
			int diffY = ceil(location.y - beforeLocation.y);
			if(_windowAction == RV_WINDOW_ACTION_MOVE){
				[_ddclientPort sendUIEvent:DD_WINDOW_MOVE eventOwner:0 param1:diffX param2:diffY];
			}
			else if(_windowAction == RV_WINDOW_ACTION_RESIZE) {
				[_ddclientPort sendUIEvent:DD_WINDOW_RESIZE eventOwner:0 param1:diffX param2:diffY];
			}
		}
	}
	beforeLocation = location;
	beforeNumTouches = numTouches;
}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	if(_mode == RV_MOUSE_MODE){
		CGPoint pt = [((UITouch*)[touches anyObject]) locationInView:_desktopView];
		[self sendMouseEvent:DD_MOUSE_BUTTON_MOVE x:pt.x y:pt.y];
		[self sendMouseEvent:DD_MOUSE_BUTTON_DOWN x:pt.x y:pt.y];
	}
	[super touchesBegan:touches withEvent:event];
}


- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	if(_mode == RV_MOUSE_MODE){
		CGPoint pt = [((UITouch*)[touches anyObject]) locationInView:_desktopView];
		[self sendMouseEvent:DD_MOUSE_BUTTON_UP x:pt.x y:pt.y];
	}
	[super touchesBegan:touches withEvent:event];
}


- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    if (scrollView == _scrollView) {
        return _desktopView;
    }
    return nil;
}


- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
	[self updatePeepFrame];
}


- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
	[self updatePeepFrame];
}


- (void)sendMouseEvent:(enum DDUIEventType)eventType x:(int)x y:(int)y
{
	if (eventType == DD_MOUSE_BUTTON_MOVE){
		[_ddclientPort sendUIEvent:eventType eventOwner:DD_MOUSE_LEFT_BUTTON param1:x param2:y];	
	}
	else{
		if (_mouseAction == RV_MOUSE_ACTION_LEFT) {
			[_ddclientPort sendUIEvent:eventType eventOwner:DD_MOUSE_LEFT_BUTTON param1:x param2:y];
		}
		if (_mouseAction == RV_MOUSE_ACTION_RIGHT) {
			[_ddclientPort sendUIEvent:eventType eventOwner:DD_MOUSE_RIGHT_BUTTON param1:x param2:y];
		}
		if (_mouseAction == RV_MOUSE_ACTION_MIDDLE) {
			[_ddclientPort sendUIEvent:eventType eventOwner:DD_MOUSE_MIDDLE_BUTTON param1:x param2:y];
		}
	}
}


- (void)updatePeepFrame
{
	int x = _scrollView.contentOffset.x / _scrollView.zoomScale;
	int y = _scrollView.contentOffset.y / _scrollView.zoomScale;
	int w = ceil(_scrollView.frame.size.width / MAX(_scrollView.zoomScale, 1.0));
	int h = ceil(_scrollView.frame.size.height / MAX(_scrollView.zoomScale, 1.0));
	
	x = MAX(0, x);
	y = MAX(0, y);
	w = MIN(w, _ddclientPort.screenSize.width - x);
	h = MIN(h, _ddclientPort.screenSize.height - y);
	
	[_ddclientPort changeDownloadFrame:CGRectMake(x, y, w, h) zoomScale:_scrollView.zoomScale];
	[_scrollView setNeedsDisplay];
	[self updateView];
}


@end
